const Move = require('./move')

const discord = require('discord.js')
const _ = require('lodash')
const prompt = require('../util/prompt')

// The base class! Each method is called to request a decision from the AI.
// Instanced on a battle-by-battle, per-character basis.
class AI {
  constructor(char, battle, team) {
    this.char = char
    this.battle = battle
    this.team = team
  }

  // Returns { move: Move, targets: [Character] } to perform next.
  async moveChoice(self, battle) {}
}

// For player-controlled characters. Interfaces with Discord.
class DiscordAI extends AI {
  async moveChoice() {
    // Move
    const moves = await Promise.all(this.char.moveIDs.map(id => Move.findOne({_id: id})))

    const { move } = await prompt({
      channel: this.team.channel,
      user: this.char,
      title: this.char.getName(this.battle.game.guild),
      description: 'Next move:',
      choices: moves.map(move => ({emote: move.emote, name: `**${move.name}** - ${move.description}`, move}))
    })

    // Target(s)
    let targetPromptDesc = `Use _${move.name}_ on:`

    if (move.target.numberMin === 1 && move.target.numberMax > 1) {
      targetPromptDesc += ` (pick up to ${move.target.numberMax})`
    } else if (move.target.numberMax > move.target.numberMin) {
      targetPromptDesc += ` (pick ${move.target.numberMin} - ${move.target.numberMax})`
    }

    let targetable
    switch (move.target.type) {
      // Only yourself.
      case 'self':
      targetable = [this.char]
      break

      // Everyone in your party but yourself.
      case 'party':
      targetable = this.team.party.members
        .filter(m => m.discordID !== this.char.discordID)
      break

      // Anyone in a different party (ie. hostile),
      case 'enemy':
      targetable = _.flatten(this.battle.teams
        .map(({ party }) => party)
        .filter(party => party._id !== this.team.party._id)
        .map(party => party.members))
      break

      // Anyone else in the battle.
      case 'any':
      targetable = this.battle.everyone
        .filter(m => m._id !== this.char._id)
      break
    }

    /*if (targetable.length === 1) {
      // Only one character can be targeted, so just choose them.
      return {move, targets: targetable}
    } else */if (targetable.length === 0) {
      // No-one can be targeted, so ask for a different move choice.
      // TODO: handle this case better?
      const msg = await this.team.channel.send('No targets for that move!')
      const ret = await this.moveChoice()

      await msg.delete()
      return ret
    }

    // TODO: add a back button

    const targets = await prompt.multi({
      channel: this.team.channel,
      user: this.char,
      title: this.char.getName(this.battle.game.guild),
      description: targetPromptDesc,
      choices: await Promise.all(targetable
        .map(async (char, i) => ({
          emote: await char.getEmote(this.battle.game),
          name: char.getName(this.battle.game.guild),
          char,
        }))),
      chooseMin: move.target.numberMin,
      chooseMax: move.target.numberMax,
    })

    return {move, targets: targets.map(choice => choice.char)}
  }
}

module.exports = {DiscordAI}
